package com.lanou.list;

import java.util.Arrays;

/**
 * @author zyj
 * @date 2022年05月17日 16:33
 */
public class ArrayList<E> implements List<E> {
    //数组来存储元素
    //创建ArrayList对象的给定泛型，对象存入数组里面
    private Object[] elementData;
    private final int DEFAULT_CAPACITY = 10;
    private final Object[] EMPTY_ELEMENTDATA = {};
    private int size;

    /**
     * ArrayList底层代码实现的时候，无参构造方法（没有传容量）
     * 默认创建的长度为零的数组
     */
    public ArrayList() {
        elementData = EMPTY_ELEMENTDATA;
    }

    /**
     * 给定容量
     *
     * @param capacity
     */
    public ArrayList(int capacity) {
        elementData = new Object[capacity];
    }

    /**
     * 获取集合的大小，元素的个数
     *
     * @return
     */
    @Override
    public int size() {
        return size;
    }

    /**
     * 判断该容器是否为空
     *
     * @return
     */
    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * 集合里面是否包含element
     *
     * @param element
     * @return
     */
    @Override
    public boolean contains(E element) {
        return indexOf(element) != -1;
    }

    /**
     * 往末尾添加元素
     *
     * @param element
     */
    @Override
    public void add(E element) {
        add(size, element);
    }

    @Override
    public E get(int index) {
        rangeCheck(index);
        return (E) elementData[index];
    }


    /**
     * @param index
     * @param element
     * @return 返回的是旧元素
     */
    @Override
    public E set(int index, E element) {
        rangeCheck(index);
        E oldEle = (E) elementData[index];
        elementData[index] = element;
        return oldEle;
    }

    /**
     * 往指定位置添加元素
     *
     * @param index
     * @param element
     */
    @Override
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        //扩容
        ensureCapacityInternal(size + 1);
        //腾位置
        System.arraycopy(elementData, index, elementData, index + 1, (size - index));
        elementData[index] = element;
        size++;
    }


    /**
     * 返回的移除的元素
     * @param index
     * @return
     */
    @Override
    public E remove(int index) {
        rangeCheck(index);
        E ele = get(index);
        System.arraycopy(elementData,index+1,elementData,index,size-index-1);
        elementData[--size] = null;
        return ele;
    }

    /**
     * 返回element在数组第一次出现的位置
     *
     * @param element
     * @return
     */
    @Override
    public int indexOf(E element) {
        if (element == null) {
            for (int i = 0; i < size; i++) {
                if (elementData[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (element.equals(elementData[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 清除所有元素
     */
    @Override
    public void clear() {
        //需要把数组里面的元素全部置为null
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        size = 0;
    }

    private void rangeCheck(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    }

    private void rangeCheckForAdd(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    }


    private void ensureCapacityInternal(int minCapacity) {

        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    /**
     * minCapacity 容器需要的容量
     * minCapacity < elementData.length 说明数组有位置存元素 不需要扩容
     *
     * @param minCapacity
     */
    private void ensureExplicitCapacity(int minCapacity) {
        if (elementData.length < minCapacity) {
            grow(minCapacity);
        }

    }

    /**
     * 扩容
     */
    private void grow(int minCapacity) {
        //获取容器的容量
        int oldCapity = elementData.length;
        int newCapity = oldCapity + (oldCapity >> 1);
        if (newCapity < minCapacity) {
            newCapity = minCapacity;
        }
        elementData = Arrays.copyOf(elementData, newCapity);
    }

    /**
     * 计算需要多少容量
     *
     * @param elementData
     * @param minCapacity
     * @return
     */
    private int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }



}
